package com.kk.demo.java8.forkjoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

/**
 * 需求是：计算1+2+3+4的结果。
 * 
 * 使用Fork／Join框架首先要考虑到的是如何分割任务，
 * 如果我们希望每个子任务最多执行两个数的相加，
 * 那么我们设置分割的阈值是2，由于是4个数字相加，
 * 所以Fork／Join框架会把这个任务fork成两个子任务，
 * 子任务一负责计算1+2，
 * 子任务二负责计算3+4，
 * 然后再join两个子任务的结果。
 * 
 * @author kk
 * @version 0.0.1
 * @date 2017年3月7日
 */
public class CountTask extends RecursiveTask<Integer> {

    /**
     * 阈值
     */
    private static final int THRESHOLD = 2;

    /**
     * 开始计算,因为是最小的拆分单位为2，则只需要两个数，即两个加数
     */
    private int start;

    /**
     * 结束值
     */
    private int end;

    public CountTask(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {

        int sum = 0;

        // 检查当前任务是否已经足够小
        boolean canCompute = (end - start) <= THRESHOLD;

        if (canCompute) {
            for (int i = start; i <= end; i++) {
                sum = sum + i;
            }
        }
        // 如果当前的任务还足够大，需要进行一步的拆分
        else {
            // 如果任务大于阈值，就拆分出两个任务
            int mid = (start + end) / 2;

            CountTask countStart = new CountTask(start, mid);
            CountTask countEnd = new CountTask(mid + 1, end);

            // 进行分隔执行计算
            countStart.fork();
            countEnd.fork();

            // 获取结果
            int countStartRsp = countStart.join();
            int countEndRsp = countEnd.join();

            sum = countStartRsp + countEndRsp;
        }

        return sum;
    }

    public static void main(String[] args) {
        ForkJoinPool forkjoinPool = new ForkJoinPool();

        // 生成任务计算1到5的结果
        CountTask count = new CountTask(1, 5);

        Future<Integer> result = forkjoinPool.submit(count);

        try {
            System.out.println(result.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
